package com.gitee.sidihuo.sse.base;

import com.alibaba.fastjson.JSONObject;
import com.gitee.sidihuo.sse.SseContextHolder;
import com.gitee.sidihuo.sse.SseOkHttpPara;
import lombok.extern.slf4j.Slf4j;
import okhttp3.Response;
import okhttp3.sse.EventSource;
import okhttp3.sse.EventSourceListener;
import org.springframework.lang.Nullable;

import java.io.IOException;
import java.util.ArrayList;

/**
 *  流式响应监听器
 */
@Slf4j
public class SseOkHttpEventSourceListener<T> extends EventSourceListener {

    private SseOkHttpPara sseOkHttpPara;

    public SseOkHttpEventSourceListener(SseOkHttpPara sseOkHttpPara) {
        super();
        this.sseOkHttpPara = sseOkHttpPara;
    }

    @Override
    public void onOpen(EventSource eventSource, Response response) {
        super.onOpen(eventSource, response);
        log.info("建立sse连接 onOpen {}", sseOkHttpPara.getId());
        sseOkHttpPara.setStreamResults(new ArrayList<>());
    }

    @Override
    public void onEvent(EventSource eventSource, @Nullable String id, @Nullable String type, String data) {
        super.onEvent(eventSource, id, type, data);
        log.info("sse连接响应 {} ID={} TYPE={} DATA= {}", sseOkHttpPara.getId(), id, type, data);
        try {
            sseOkHttpPara.getStreamOriginResults().add(data);
            SseHttpResponseFunction<T> sseHttpResponseFunction = sseOkHttpPara.getSseHttpResponseFunction();
            T response = sseHttpResponseFunction.wrap(data);
            sseOkHttpPara.getStreamResults().add(response);
            SseContextHolder.getInstance().pushMessage(sseOkHttpPara.getId(), JSONObject.toJSONString(response));
        } catch (IOException e) {
            log.warn("sse连接响应 转发IO异常 {}", sseOkHttpPara.getId(), e);
        }
    }

    @Override
    public void onClosed(EventSource eventSource) {
        super.onClosed(eventSource);
        sseOkHttpPara.getCountDownLatch().countDown();
        log.info("关闭sse连接 onClosed {}", sseOkHttpPara.getId());
    }

    @Override
    public void onFailure(EventSource eventSource, @Nullable Throwable t, @Nullable Response response) {
        super.onFailure(eventSource, t, response);
        sseOkHttpPara.getCountDownLatch().countDown();
        int responseCode = response.code();
        String responseMessage = t == null ? "null" : t.getMessage();
        String throwableName = t == null ? "null" : t.getClass().getName();
        log.warn("sse连接异常 onFailure {} {} {} {}", sseOkHttpPara.getId(), responseCode, responseMessage, throwableName, t);
    }
}
